"""
Module that maintains bookmarks list
"""

from __future__ import with_statement
import sys
import gobject
import gtk

from . import log
from . import database
from . import collection

notifier = None
main_bookmarks_menu = None

class BookmarksNotifier(gobject.GObject): 
    """
    Class that sends notifications (as signals) about all changes in bookmarks.
    Singleton-like.
    """
    __gsignals__ = {
        'bookmarks-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, tuple())
        }

    def __init__(self):
        gobject.GObject.__init__(self)
        
    def emit_bookmarks_changed_signal(self):
        self.emit("bookmarks-changed")
        
def get_notifier():
    """
    Return BookmarksNotifier object. It must be just one.
    """
    global notifier
    
    if notifier is None:
        notifier = BookmarksNotifier()
        
    return notifier

def add(target, title, group=-1, order_in_group=0, autocommit=True):
    """
    Add bookmark with given title and target into the database
    """
    
    db = database.get_connection()
    cursor = db.cursor()
    query = "INSERT INTO bookmarks VALUES (NULL, ?, ?, ?, ?)"
    database.execute(query, args=(target, title, group, order_in_group), cursor=cursor)
    
    if autocommit:
        db.commit()

        if cursor.rowcount > 0:
            get_notifier().emit_bookmarks_changed_signal()

def add_many(bookmarks_list, replace=False):
    """
    Add many bookmarks at once
    
    @param bookmarks_list: list of bookmarks specs (i.e. list of sequences [target, title, group_id] )
    @param replace: if True then all existing bookmarks will be deleted
    """
    db = database.get_connection()
    cursor = db.cursor()
    
    bd = dict()

    with db:
        if replace:
            query = "DELETE FROM bookmarks"
            database.execute(query, cursor=cursor)
            
        for target, title, group_id in bookmarks_list:
            if not group_id in bd:
                bd[group_id] = 0
            
            add(target, title, group_id, bd[group_id], autocommit=False)
            bd[group_id] += 1
    
def get_all_bookmarks():
    """
        Return list of all bookmarks.
        
        @return: tuple of tuples (id, target, title, bookmark_group_id)
    """
    db = database.get_connection()
    cursor = db.cursor()
    query = "SELECT bookmark_id, target, title, bookmark_group_id FROM bookmarks"
    database.execute(query, cursor=cursor)
    
    return [row for row in cursor]

def delete_all_bookmarks(autocommit=True):
    """
    Delete all bookmarks from the database
    """
    db = database.get_connection()
    cursor = db.cursor()
    query = "DELETE FROM bookmarks"
    database.execute(query, cursor=cursor)
    if autocommit:
        db.commit()

def get_bookmark_groups(parent_group_id, cursor=None):
    """
    Get all bookmark groups list owned by group parent_group_id, parent_group_id==-1 means root groups
    
    @param parent_group_id: db id of parent group, -1 for top-level groups
    @return: list of [group_id, title, subgroups_list]
    """
    if cursor is None:
        db = database.get_connection()
        cursor = db.cursor()

    query = "SELECT bookmark_group_id, title FROM bookmark_groups WHERE parent_group_id=?"
    database.execute(query, args=(parent_group_id,), cursor=cursor)
    groups = list()
    
    for group_id, title in [row for row in cursor]:
        groups.append([group_id, title, get_bookmark_groups(group_id, cursor)])
        
    return groups
    
def delete_bookmark_groups(autocommit=True):
    """
    Delete all bookmark groups from the database
    """
    db = database.get_connection()
    cursor = db.cursor()
    query = "DELETE FROM bookmark_groups"
    database.execute(query, cursor=cursor)
    if autocommit:
        db.commit()

def recreate_bookmark_groups(groups):
    """
    Create bookmark groups from scratch. groups represents groups tree:
        GROUP ::: [group_title, group_id, ANYDATA, GROUPSLIST]
        GROUPSLIST ::: [GROUP, GROUP, ...]
    """
    db = database.get_connection()
    cursor = db.cursor()
    query = "INSERT INTO bookmark_groups (title, parent_group_id) VALUES (?, ?)"

    def __create_groups(groups_tree, top_parent):
        new_groups_tree = []
        for group_title, group_id, DATA, subgroups in groups_tree:
            
            database.execute(query, args=(group_title, parent), cursor=cursor)
            group_id = database.last_insert_id(cursor)
            new_groups_tree.append( [group_title, group_id, DATA, __create_groups(subgroups, parent=group_id)] )
            
        return new_groups_tree
    
    with db:
        delete_bookmark_groups(False)
        groups = __create_groups(groups, -1)

    return groups

def create_group_menus(menu, groups):
    """
    Create bookmarks group menu items
    
    @return: list of tuples (bookmark_group_id, group_menu), where group_menu is submenu that corresponds
        to bookmark_group_id
    """
    g = list()
    for group_id, title, sub_groups in groups:
        mi = gtk.MenuItem(title)
        submenu = gtk.Menu()
        g += create_group_menus(submenu, sub_groups)
        mi.set_submenu(submenu)
        menu.add(mi)
        g.append((group_id, submenu))
        
    return g

def rebuild_bookmarks_menus(bookmark_activate_func, manage_bookmarks_func):
    # build bookmark groups
    bookmark_groups = get_bookmark_groups(-1)

    if isinstance(main_bookmarks_menu, gtk.Menu):
        main_bookmarks_menu.foreach(lambda x: main_bookmarks_menu.remove(x))
        g = create_group_menus(main_bookmarks_menu, bookmark_groups)
        groups_map = dict()
        for group_id, group_menu in g:
            groups_map[group_id] = group_menu
            
        groups_map[-1] = main_bookmarks_menu
        
        for id, target, title, bookmark_group_id in get_all_bookmarks():
            # first find menu where to place bookmark
            if not bookmark_group_id in groups_map:
                group_menu = main_bookmarks_menu
            else:
                group_menu = groups_map[bookmark_group_id]
                
            # append
            mi = gtk.MenuItem(title)
            mi.set_data("target", target)
            mi.set_data("id", id)
            mi.connect("activate", bookmark_activate_func)
            group_menu.append(mi)
            
        main_bookmarks_menu.add(gtk.SeparatorMenuItem())
        mi = gtk.MenuItem(_("Manage bookmarks"))
        mi.set_tooltip_text(_("Edit bookmarks and bookmarks folders"))
        mi.connect("activate", manage_bookmarks_func)
        main_bookmarks_menu.add(mi)
        main_bookmarks_menu.show_all()
                    
def set_main_bookmarks_menu(menu):
    global main_bookmarks_menu
    
    main_bookmarks_menu = menu
    
